home *** CD-ROM | disk | FTP | other *** search
- /*
- * fractalobject.c
- *
- * Peter Janssen
- *
- */
- #include "geom.h"
- #include "fractalobject.h"
- #include "bounds.h"
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
-
-
- FractalClosure *Fractalclosure;
- PointPool *Pointpool;
- TrianglePool *Trianglepool;
- EntityPool *Entitypool;
-
-
- static Methods *iFractalObjMethods = NULL;
- static char fractalobjName[] = "fractalobject";
- static unsigned long raynumber = 1;
- static FirstPoint *SideList;
- unsigned long FractalObjTests, FractalObjHits;
- static Float Scale;
-
-
- /*
- * Random Generator
- */
-
- #define rand_m (unsigned long)2147483647
- #define rand_q (unsigned long)127773
-
- #define rand_a (unsigned int)16807
- #define rand_r (unsigned int)2836
-
- /*
- * F(z) = (az)%m
- * = az-m(az/m)
- *
- * F(z) = G(z)+mT(z)
- * G(z) = a(z%q)- r(z/q)
- * T(z) = (z/q) - (az/m)
- *
- * F(z) = a(z%q)- rz/q+ m((z/q) - a(z/m))
- * = a(z%q)- rz/q+ m(z/q) - az
- */
-
- static long rand_seed;
-
- static Float rand_number()
- {
- long lo, hi, test;
- static Float inv_rand_m;
- inv_rand_m = 1.0 / rand_m;
-
- hi = rand_seed/rand_q;
- lo = rand_seed%rand_q;
-
- test = rand_a*lo - rand_r*hi;
-
- if (test > 0)
- rand_seed = test;
- else
- rand_seed = test + rand_m;
-
- return (rand_seed * inv_rand_m * 2) - 1;
- }
-
- /*
- * Calculate the boundingbox and the size of a voxel
- * for every subobject in the fractalobject
- */
- static void CalculateBoundingBoxesAndVoxelSizes(fractalobj)
- FractalObj *fractalobj;
- {
- int i, j, CurrPointNumber;
- SubObject *CurrSubobject;
- FractalPoint *Points;
-
- Points = Fractalclosure->Pointpool->Points;
- for(CurrSubobject = fractalobj->SubObjects; CurrSubobject; CurrSubobject = CurrSubobject->Next) {
- for (j = 0; j <= 2; j++) CurrSubobject->Bounds[LOW][j] = MAXVALUE;
- for (j = 0; j <= 2; j++) CurrSubobject->Bounds[HIGH][j] = -MAXVALUE;
- for (i = 0; i < CurrSubobject->Trianglepool->NumberOfTriangles; i++) {
- for (j = 0; j <= 2; j++) {
- CurrPointNumber = CurrSubobject->Trianglepool->Triangles[i].Point[j];
- CurrSubobject->Bounds[LOW][X] = min(CurrSubobject->Bounds[LOW][X], Points[CurrPointNumber].x);
- CurrSubobject->Bounds[HIGH][X] = max(CurrSubobject->Bounds[HIGH][X], Points[CurrPointNumber].x);
- CurrSubobject->Bounds[LOW][Y] = min(CurrSubobject->Bounds[LOW][Y], Points[CurrPointNumber].y);
- CurrSubobject->Bounds[HIGH][Y] = max(CurrSubobject->Bounds[HIGH][Y], Points[CurrPointNumber].y);
- CurrSubobject->Bounds[LOW][Z] = min(CurrSubobject->Bounds[LOW][Z], Points[CurrPointNumber].z);
- CurrSubobject->Bounds[HIGH][Z] = max(CurrSubobject->Bounds[HIGH][Z], Points[CurrPointNumber].z);
- }
- }
- CurrSubobject->VoxelSize[X] = (CurrSubobject->Bounds[HIGH][X] - CurrSubobject->Bounds[LOW][X]) /
- CurrSubobject->XSize;
- CurrSubobject->VoxelSize[Y] = (CurrSubobject->Bounds[HIGH][Y] - CurrSubobject->Bounds[LOW][Y]) /
- CurrSubobject->YSize;
- CurrSubobject->VoxelSize[Z] = (CurrSubobject->Bounds[HIGH][Z] - CurrSubobject->Bounds[LOW][Z]) /
- CurrSubobject->ZSize;
- }
- }
-
-
- /*
- * Calculate new points on the midpoints of the
- * three edges of the triangle
- */
- static void CalculatePoints(fractalobj, NewPoints, FTriangle, Delta)
- FractalObj *fractalobj;
- int NewPoints[3];
- FractalTriangle *FTriangle;
- DeltaInfo Delta[3];
- {
- int i, j, fpoint, lpoint, NPoints, Pointsallocated;
- FirstPoint *Currfp, *chasingfp, *Newfp;
- LastPoint *Currlp, *chasinglp, *Newlp;
- FractalPoint *Points, *TPoints;
- PointPool *Pointpool;
- Float displacement, size1, size2;
- Vector n1, n2;
-
- Pointpool = Fractalclosure->Pointpool;
- NPoints = Pointpool->NumberOfPoints;
- Pointsallocated = Pointpool->PointsAllocated;
- Points = Pointpool->Points;
- for(i=0; i<=2; i++) {
- fpoint = min(FTriangle->Point[(i + 1)%3], FTriangle->Point[i]);
- lpoint = max(FTriangle->Point[(i + 1)%3], FTriangle->Point[i]);
- for(Currfp = SideList; fpoint > Currfp->Point; chasingfp = Currfp,
- Currfp = Currfp->Next);
- if (Currfp->Point == fpoint) {
- /*
- * sidelist has an entry with firstpoint
- */
- chasinglp = NULL;
- for(Currlp = Currfp->Info; Currlp && (Currlp->Point < lpoint);
- chasinglp = Currlp, Currlp = Currlp->Next);
- if (Currlp && (Currlp->Point == lpoint)) {
- /*
- * sidelist has an entry for pointpair fpoint, lpoint
- */
- NewPoints[i] = Currlp->NewPoint;
- continue;
- }
- }
-
- /*
- * Calculate New Point
- */
- displacement = Delta[i].distance * pow((fractalobj->Excentricity * Delta[i].distance * Scale), fractalobj->Dimension);
- /* n1 */
- if (Delta[i].z != 0) {
- n1.x = -Delta[i].z;
- n1.y = -Delta[i].z;
- n1.z = Delta[i].x + Delta[i].y;
- } else if (Delta[i].y != 0) {
- n1.x = -Delta[i].y;
- n1.y = Delta[i].x + Delta[i].z;
- n1.z = -Delta[i].y;
- } else {
- n1.x = Delta[i].y + Delta[i].z;
- n1.y = -Delta[i].x;
- n1.z = -Delta[i].x;
- }
- VecNormalize(&n1);
- /* n2 */
- VecCross(&Delta[i], &n1, &n2);
- VecNormalize(&n2);
- size1 = rand_number();
- size2 = rand_number();
- CheckPoints(Points, NPoints, Pointsallocated);
- Points[NPoints].x = (Points[fpoint].x + Points[lpoint].x) / 2 +
- displacement * size1 * n1.x + displacement * size2 * n2.x;
- Points[NPoints].y = (Points[fpoint].y + Points[lpoint].y) / 2 +
- displacement * size1 * n1.y + displacement * size2 * n2.y;
- Points[NPoints].z = (Points[fpoint].z + Points[lpoint].z) / 2 +
- displacement * size1 * n1.z + displacement * size2 * n2.z;
- NewPoints[i] = NPoints;
-
- /*
- * Currfp points to position equal to or just bigger than fpoint
- */
- Newlp = (LastPoint *)share_malloc(sizeof(LastPoint));
- Newlp->Point = lpoint;
- if (Currfp->Point == fpoint) {
- /*
- * Currlp points tot position equal to or just bigger than
- * lpoint or is equal to NULL
- * Insert between chasinglp and Currlp
- */
- if (chasinglp == NULL)
- /*
- * the first in line
- */
- Currfp->Info = Newlp;
- else
- chasinglp->Next = Newlp;
- Newlp->Next = Currlp;
- } else {
- Newfp = (FirstPoint *)share_malloc(sizeof(FirstPoint));
- chasingfp->Next = Newfp;
- Newfp->Next = Currfp;
- Newfp->Info = Newlp;
- Newfp->Point = fpoint;
- Newlp->Next = NULL;
- }
- Newlp->NewPoint = NPoints++;
- }
- Pointpool->NumberOfPoints = NPoints;
- Pointpool->PointsAllocated = Pointsallocated;
- Pointpool->Points = Points;
- }
-
-
- /*
- * Take triangulated object and distort it
- */
- static void BuildFractalObject(fractalobj)
- FractalObj *fractalobj;
- {
- Float Maxsize, Delta_x, Delta_y, Delta_z, distance;
- int Changed, Poolchanged, ONTriangles, NTriangles, Trianglesallocated;
- FractalPoint *FPoints;
- SubObject *CurrSubobject;
- TrianglePool *Trianglepool;
- FractalTriangle *FTriangles;
- DeltaInfo Delta[3];
- int i, j, k, NewPoints[3], t1, t2;
- FirstPoint *Currfp, *chasingfp;
- LastPoint *Currlp, *chasinglp;
-
- Maxsize = fractalobj->MaximumSize;
- Changed = TRUE;
- Scale = 0;
- FPoints = Pointpool->Points;
- for (CurrSubobject = fractalobj->SubObjects; CurrSubobject; CurrSubobject = CurrSubobject->Next) {
- FTriangles = CurrSubobject->Trianglepool->Triangles;
- for (i=0; i < CurrSubobject->Trianglepool->NumberOfTriangles; i++) {
- for(j = 0; j <= 2; j++) {
- t1 = FTriangles[i].Point[j];
- t2 = FTriangles[i].Point[(j+1)%3];
- Delta_x = FPoints[t1].x - FPoints[t2].x;
- Delta_y = FPoints[t1].y - FPoints[t2].y;
- Delta_z = FPoints[t1].z - FPoints[t2].z;
- distance = sqrt(Delta_x * Delta_x +
- Delta_y * Delta_y +
- Delta_z * Delta_z);
- Scale = max(Scale, distance);
- }
- }
- }
- Scale = 1.0 / Scale;
-
- while (Changed) {
- Changed = FALSE;
- for (CurrSubobject = fractalobj->SubObjects; CurrSubobject; CurrSubobject = CurrSubobject->Next) {
- Trianglepool = CurrSubobject->Trianglepool;
- if (Trianglepool->PoolChanged) {
- Poolchanged = FALSE;
- ONTriangles = NTriangles = Trianglepool->NumberOfTriangles;
- Trianglesallocated = Trianglepool->TrianglesAllocated;
- FTriangles = Trianglepool->Triangles;
- for (i=0; i < ONTriangles; i++) {
- FPoints = Pointpool->Points;
- for(j = 0; j <= 2; j++) {
- t1 = FTriangles[i].Point[j];
- t2 = FTriangles[i].Point[(j+1)%3];
- Delta[j].x = FPoints[t1].x - FPoints[t2].x;
- Delta[j].y = FPoints[t1].y - FPoints[t2].y;
- Delta[j].z = FPoints[t1].z - FPoints[t2].z;
- Delta[j].distance = sqrt(Delta[j].x * Delta[j].x +
- Delta[j].y * Delta[j].y +
- Delta[j].z * Delta[j].z);
- }
- if ((Delta[0].distance > Maxsize) ||
- (Delta[1].distance > Maxsize) ||
- (Delta[2].distance > Maxsize)) {
- Poolchanged = Changed = TRUE;
- if (NTriangles + 3 >= Trianglesallocated) {
- Trianglesallocated += TrianglesToAllocate;
- FTriangles = (FractalTriangle *)realloc((char *)FTriangles, Trianglesallocated * sizeof(FractalTriangle));
- }
- NTriangles += 3;
- CalculatePoints(fractalobj, NewPoints, &FTriangles[i], Delta);
- FTriangles[NTriangles - 1].Point[0] = NewPoints[0];
- FTriangles[NTriangles - 1].Point[1] = NewPoints[1];
- FTriangles[NTriangles - 1].Point[2] = NewPoints[2];
- FTriangles[NTriangles - 3].Point[0] = NewPoints[0];
- FTriangles[NTriangles - 3].Point[1] = FTriangles[i].Point[1];
- FTriangles[NTriangles - 3].Point[2] = NewPoints[1];
- FTriangles[NTriangles - 2].Point[0] = NewPoints[2];
- FTriangles[NTriangles - 2].Point[1] = NewPoints[1];
- FTriangles[NTriangles - 2].Point[2] = FTriangles[i].Point[2];
- FTriangles[i].Point[1] = NewPoints[0];
- FTriangles[i].Point[2] = NewPoints[2];
- }
- }
- Trianglepool->PoolChanged = Poolchanged;
- Trianglepool->NumberOfTriangles = NTriangles;
- Trianglepool->TrianglesAllocated = Trianglesallocated;
- Trianglepool->Triangles = FTriangles;
- }
- }
- /*
- * release sidelist and setup new one
- */
- for(Currfp = SideList->Next; Currfp->Point != MAXVALUE; chasingfp = Currfp, Currfp = Currfp->Next, free(chasingfp))
- for(Currlp = Currfp->Info; Currlp; chasinglp = Currlp,
- Currlp = Currlp->Next, free(chasinglp));
- SideList->Next = Currfp;
- }
- CalculateBoundingBoxesAndVoxelSizes(fractalobj);
- }
-
-
- /*
- * Convert worldcoordinates to gridcoordinates
- */
- static void Pos2Grid(subobj, pos, index)
- SubObject *subobj;
- Float pos[3];
- int index[3];
- {
-
- index[X] = (int)(Fx2voxel(subobj, pos[0]));
- index[Y] = (int)(Fy2voxel(subobj, pos[1]));
- index[Z] = (int)(Fz2voxel(subobj, pos[2]));
-
- if (index[X] == subobj->XSize)
- index[X]--;
- if (index[Y] == subobj->YSize)
- index[Y]--;
- if (index[Z] == subobj->ZSize)
- index[Z]--;
- }
-
-
-
- /*
- * Put triangles of fractalobject in voxels
- * for efficient raytracing
- */
- static void ConvertFractalObject(fractalobj)
- FractalObj *fractalobj;
- {
- int i, x, y, z, low[3], high[3];
- Float bounds[2][3];
- SubObject *CurrSubobject;
- FractalTriangle *Triangles, *CurrTriangle;
- TriangleInfo *Triangleinfo;
- TriangleClosure *Triangleclosure;
- FractalPoint *Points;
- int p0, p1, p2;
-
- Points = Fractalclosure->Pointpool->Points;
- for(CurrSubobject = fractalobj->SubObjects; CurrSubobject; CurrSubobject = CurrSubobject->Next) {
- Triangles = CurrSubobject->Trianglepool->Triangles;
- CurrSubobject->Cells = (TriangleClosure ****)share_malloc(CurrSubobject->XSize *
- sizeof(TriangleClosure ***));
- for (x = 0; x < CurrSubobject->XSize; x++) {
- CurrSubobject->Cells[x] = (TriangleClosure ***)share_malloc(CurrSubobject->YSize *
- sizeof(TriangleClosure **));
- for (y = 0; y < CurrSubobject->YSize; y++)
- CurrSubobject->Cells[x][y] = (TriangleClosure **)share_calloc(
- CurrSubobject->ZSize , sizeof(TriangleClosure *));
- }
- for (i = 0; i < CurrSubobject->Trianglepool->NumberOfTriangles; i++) {
- CurrTriangle = &Triangles[i];
- p0 = CurrTriangle->Point[0];
- p1 = CurrTriangle->Point[1];
- p2 = CurrTriangle->Point[2];
- bounds[LOW][X] = min3(Points[p0].x, Points[p1].x, Points[p2].x);
- bounds[HIGH][X] = max3(Points[p0].x, Points[p1].x, Points[p2].x);
- bounds[LOW][Y] = min3(Points[p0].y, Points[p1].y, Points[p2].y);
- bounds[HIGH][Y] = max3(Points[p0].y, Points[p1].y, Points[p2].y);
- bounds[LOW][Z] = min3(Points[p0].z, Points[p1].z, Points[p2].z);
- bounds[HIGH][Z] = max3(Points[p0].z, Points[p1].z, Points[p2].z);
-
- Pos2Grid(CurrSubobject, bounds[LOW], low);
- Pos2Grid(CurrSubobject, bounds[HIGH], high);
-
- Triangleinfo = (TriangleInfo *)share_malloc(sizeof(TriangleInfo));
- Triangleinfo->Point[0] = p0;
- Triangleinfo->Point[1] = p1;
- Triangleinfo->Point[2] = p2;
- Triangleinfo->Counter = 0;
- for (x = low[X]; x <= high[X]; x++)
- for (y = low[Y]; y <= high[Y]; y++)
- for (z = low[Z]; z <= high[Z]; z++) {
- Triangleclosure = (TriangleClosure *)share_malloc(sizeof(TriangleClosure));
- Triangleclosure->Triangle = Triangleinfo;
- Triangleclosure->Next = CurrSubobject->Cells[x][y][z];
- CurrSubobject->Cells[x][y][z] = Triangleclosure;
- }
- }
- /*
- * release trianglepool
- */
- free(CurrSubobject->Trianglepool->Triangles);
- free(CurrSubobject->Trianglepool);
- }
- }
-
-
- /*
- * Create FractalObject and return reference to it
- */
- FractalObj *FractalObjCreate(Number, Dimension, MaxSize, Excentricity, fc)
- Float MaxSize, Dimension, Excentricity;
- int Number;
- FractalClosure *fc;
- {
- FractalObj *fractalobj;
- int *TList, TriangleNumber;
- FractalTriangle *InitialTriangles, *LocalTriangles, *TTriangles;
- FractalEntity *CurrEntity;
- int NPoints, NTriangles, NEntities, i, j, LocalAllocated, LocalNTriangles;
- SubObject *Subobjects, *TSubobject;
- TriangleList *CurrTriangle, *chasingTriangle;
- int CurrPoint;
-
-
- fractalobj = (FractalObj *)share_malloc(sizeof(FractalObj));
- fractalobj->MaximumSize = MaxSize;
- fractalobj->Dimension = Dimension;
- fractalobj->Excentricity = Excentricity;
- fractalobj->Closure = fc;
- rand_seed = Number;
-
- Fractalclosure = fc;
-
- Pointpool = Fractalclosure->Pointpool;
- Trianglepool = Fractalclosure->Trianglepool;
- Entitypool = Fractalclosure->Entitypool;
- NPoints = Pointpool->NumberOfPoints;
- NTriangles = Trianglepool->NumberOfTriangles;
- NEntities = Entitypool->NumberOfEntities;
-
- if (NPoints <= 0)
- RLerror(RL_ABORT, "Illegal number of Points : %d", NPoints);
-
- if (NTriangles <= 0)
- RLerror(RL_ABORT, "Illegal number of Triangles : %d", NTriangles);
-
- if (NEntities <= 0)
- RLerror(RL_ABORT, "Illegal number of Entities : %d", NEntities);
-
- TList = (int *)Malloc(sizeof(int) * NTriangles);
-
- Subobjects = NULL;
- InitialTriangles = Trianglepool->Triangles;
- for (i=0; i < NEntities; i++) {
- CurrEntity = &Entitypool->Entities[i];
- TSubobject = (SubObject *)share_malloc(sizeof(SubObject));
- TSubobject->Trianglepool = (TrianglePool *)share_malloc(sizeof(TrianglePool));
- LocalTriangles = (FractalTriangle *)share_malloc(TrianglesToAllocate * sizeof(FractalTriangle));
- LocalAllocated = TrianglesToAllocate;
- TSubobject->XSize = CurrEntity->XSize;
- TSubobject->YSize = CurrEntity->YSize;
- TSubobject->ZSize = CurrEntity->ZSize;
- LocalNTriangles = 0;
- for (CurrTriangle = CurrEntity->Triangles; CurrTriangle;
- chasingTriangle = CurrTriangle, CurrTriangle = CurrTriangle->Next,
- free(chasingTriangle)) {
- TriangleNumber = CurrTriangle->TriangleNumber;
-
- if (TriangleNumber < 0 || TriangleNumber >= NTriangles)
- RLerror(RL_ABORT, "Illegal Triangle number : %d\n", TriangleNumber+1);
- CheckTriangles(LocalTriangles, LocalNTriangles, LocalAllocated);
-
- CurrPoint = InitialTriangles[TriangleNumber].Point[0];
- if ((CurrPoint < 0) || (CurrPoint >= NPoints))
- RLerror(RL_ABORT, "Illegal Point number : %d\n", CurrPoint+1);
- LocalTriangles[LocalNTriangles].Point[0] = CurrPoint;
-
- CurrPoint = InitialTriangles[TriangleNumber].Point[1];
- if ((CurrPoint < 0) || (CurrPoint >= NPoints))
- RLerror(RL_ABORT, "Illegal Point number : %d\n", CurrPoint+1);
- LocalTriangles[LocalNTriangles].Point[1] = CurrPoint;
-
- CurrPoint = InitialTriangles[TriangleNumber].Point[2];
- if ((CurrPoint < 0) || (CurrPoint >= NPoints))
- RLerror(RL_ABORT, "Illegal Point number : %d\n", CurrPoint+1);
- LocalTriangles[LocalNTriangles].Point[2] = CurrPoint;
-
- LocalNTriangles++;
- TList[TriangleNumber] = TRUE;
- }
- TSubobject->Trianglepool->NumberOfTriangles = LocalNTriangles;
- TSubobject->Trianglepool->TrianglesAllocated = LocalAllocated;
- TSubobject->Trianglepool->Triangles = LocalTriangles;
- TSubobject->Trianglepool->PoolChanged = TRUE;
- TSubobject->Next = Subobjects;
- Subobjects = TSubobject;
- }
- fractalobj->SubObjects = Subobjects;
- /*
- * Check if every triangle is placed in a subobject
- */
- for (i=0; i < NTriangles; i++)
- if (!TList[i]) RLerror(RL_ADVISE, "Triangle %d not placed in entity.\n", i+1);
- free(TList);
- /*
- * release triangles uit trianglepool
- */
- free(Trianglepool->Triangles);
- free(Trianglepool);
- /*
- * release entitypool
- */
- free(Entitypool->Entities);
- free(Entitypool);
- /*
- * Build empty sidelist
- */
- SideList = (FirstPoint *)share_malloc(sizeof(FirstPoint));
- SideList->Point = -1;
- SideList->Next = (FirstPoint *)share_malloc(sizeof(FirstPoint));
- SideList->Next->Point = MAXVALUE;
-
- /*
- * Distort object
- */
- BuildFractalObject(fractalobj);
- /*
- * free sidelist
- */
- free(SideList->Next);
- free(SideList);
- /*
- * Convert to voxels
- */
- ConvertFractalObject(fractalobj);
-
- return fractalobj;
- }
-
-
-
- /*
- * Intersect ray with fractalobject.
- */
- int FractalObjIntersect(fractalobj, ray, mindist, maxdist)
- FractalObj *fractalobj;
- Ray *ray;
- Float mindist, *maxdist;
- {
- int hit;
- Float offset;
- Vector curpos;
- unsigned long counter;
- SubObject *CurrSubobject;
-
- FractalObjTests++;
- hit = FALSE;
-
- /*
- * If outside of the bounding box, check to see if we
- * hit it.
- */
- VecAddScaled(ray->pos, mindist, ray->dir, &curpos);
- offset = *maxdist;
- if (OutOfBounds(&curpos, fractalobj->Bounds) &&
- !BoundsIntersect(ray, fractalobj->Bounds, mindist, &offset))
- /*
- * Ray never hit grid space.
- */
- return hit;
-
- counter = raynumber++;
-
- for (CurrSubobject = fractalobj->SubObjects; CurrSubobject; CurrSubobject = CurrSubobject->Next)
- if (SubObjectIntersect(fractalobj, CurrSubobject, ray, mindist, maxdist, counter))
- hit = TRUE;
- return hit;
- }
-
-
- /*
- * Test for intersection of ray with every of the subobjects
- *
- * (based on the code of grid.c)
- */
- int SubObjectIntersect(fractalobj, subobject, ray, mindist, maxdist, counter)
- FractalObj *fractalobj;
- SubObject *subobject;
- Ray *ray;
- Float mindist;
- Float *maxdist;
- unsigned long counter;
- {
- int hit;
- Float offset, tMaxX, tMaxY, tMaxZ;
- Float tDeltaX, tDeltaY, tDeltaZ;
- int stepX, stepY, stepZ, outX, outY, outZ, x, y, z;
- Vector curpos;
- TriangleClosure *list;
-
- hit = FALSE;
-
- /*
- * If outside of the bounding box, check to see if we
- * hit it.
- */
- VecAddScaled(ray->pos, mindist, ray->dir, &curpos);
- if (OutOfBounds(&curpos, subobject->Bounds)) {
- offset = *maxdist;
- if (!BoundsIntersect(ray, subobject->Bounds, mindist, &offset))
- /*
- * Ray never hit grid space.
- */
- return hit;
- VecAddScaled(ray->pos, offset, ray->dir, &curpos);
- } else
- offset = mindist;
-
-
- /*
- * tMaxX is the absolute distance from the ray origin we must move
- * to get to the next voxel in the X
- * direction. It is incrementally updated
- * by DDA as we move from voxel-to-voxel.
- * tDeltaX is the relative amount along the ray we move to
- * get to the next voxel in the X direction. Thus,
- * when we decide to move in the X direction,
- * we increment tMaxX by tDeltaX.
- */
- x = Fx2voxel(subobject, curpos.x);
- if (x == subobject->XSize)
- x--;
- if (fabs(ray->dir.x) < EPSILON) {
- tMaxX = FAR_AWAY;
- tDeltaX = 0.;
- } else if (ray->dir.x < 0.) {
- tMaxX = offset + (Fvoxel2x(subobject, x) - curpos.x) / ray->dir.x;
- tDeltaX = subobject->VoxelSize[X] / - ray->dir.x;
- stepX = outX = -1;
- } else {
- tMaxX = offset + (Fvoxel2x(subobject, x+1) - curpos.x) / ray->dir.x;
- tDeltaX = subobject->VoxelSize[X] / ray->dir.x;
- stepX = 1;
- outX = subobject->XSize;
- }
-
- y = Fy2voxel(subobject, curpos.y);
- if (y == subobject->YSize)
- y--;
-
- if (fabs(ray->dir.y) < EPSILON) {
- tMaxY = FAR_AWAY;
- tDeltaY = 0.;
- } else if (ray->dir.y < 0.) {
- tMaxY = offset + (Fvoxel2y(subobject, y) - curpos.y) / ray->dir.y;
- tDeltaY = subobject->VoxelSize[Y] / - ray->dir.y;
- stepY = outY = -1;
- } else {
- tMaxY = offset + (Fvoxel2y(subobject, y+1) - curpos.y) / ray->dir.y;
- tDeltaY = subobject->VoxelSize[Y] / ray->dir.y;
- stepY = 1;
- outY = subobject->YSize;
- }
-
- z = Fz2voxel(subobject, curpos.z);
- if (z == subobject->ZSize)
- z--;
- if (fabs(ray->dir.z) < EPSILON) {
- tMaxZ = FAR_AWAY;
- tDeltaZ = 0.;
- } else if (ray->dir.z < 0.) {
- tMaxZ = offset + (Fvoxel2z(subobject, z) - curpos.z) / ray->dir.z;
- tDeltaZ = subobject->VoxelSize[Z] / - ray->dir.z;
- stepZ = outZ = -1;
- } else {
- tMaxZ = offset + (Fvoxel2z(subobject, z+1) - curpos.z) / ray->dir.z;
- tDeltaZ = subobject->VoxelSize[Z] / ray->dir.z;
- stepZ = 1;
- outZ = subobject->ZSize;
- }
-
- /*
- * Do DDA-algoritm to traverse the grid
- */
- while (TRUE) {
- list = subobject->Cells[x][y][z];
- if (tMaxX < tMaxY && tMaxX < tMaxZ) {
- if (list) if (ListIntersect(fractalobj, list,ray,counter,offset,maxdist))
- hit = TRUE;
- x += stepX;
- if (*maxdist < tMaxX || x == outX)
- break;
- tMaxX += tDeltaX;
- } else if (tMaxZ < tMaxY) {
- if (list) if (ListIntersect(fractalobj, list,ray,counter,offset,maxdist))
- hit = TRUE;
- z += stepZ;
- if (*maxdist < tMaxZ || z == outZ)
- break;
- tMaxZ += tDeltaZ;
- } else {
- if (list) if (ListIntersect(fractalobj, list,ray,counter,offset,maxdist))
- hit = TRUE;
- y += stepY;
- if (*maxdist < tMaxY || y == outY)
- break;
- tMaxY += tDeltaY;
- }
- }
- return hit;
- }
-
- /*
- * Do intersection test with every triangle in the voxel
- */
- static int ListIntersect(fractalobj, list, ray, counter, mindist, maxdist)
- FractalObj *fractalobj;
- TriangleClosure *list;
- Ray *ray;
- unsigned long counter;
- Float mindist, *maxdist;
- {
- int hit;
-
- hit = FALSE;
-
- for(;list; list = list->Next) {
- /*
- * If object's counter is greater than or equal to the
- * number associated with the current grid,
- * don't bother checking again.
- */
- if (list->Triangle->Counter < counter ) {
- list->Triangle->Counter = counter;
- if (TriangleIntersect(fractalobj, list->Triangle->Point, ray, mindist, maxdist))
- hit = TRUE;
- }
- }
- return hit;
- }
-
-
- /*
- * Do intersection test with triangle
- */
- static int TriangleIntersect(fractalobj, point, ray, mindist, maxdist)
- FractalObj *fractalobj;
- int point[3];
- Ray *ray;
- Float mindist, *maxdist;
- {
- Vector edge1, edge2, edge3;
- Float k, s;
- Vector normal, absnorm;
- Vector pos, dir;
- Float qi1, qi2, b0, b1, b2;
- FractalPoint *Points;
- FractalPoint p0, p1, p2;
-
-
- Points = fractalobj->Closure->Pointpool->Points;
- p0 = Points[point[0]];
- p1 = Points[point[1]];
- p2 = Points[point[2]];
- VecSub(p1, p0, &edge1);
- VecSub(p2, p1, &edge2);
- VecSub(p0, p2, &edge3);
-
- /*
- * Find plane normal.
- */
- VecCross(&edge1, &edge2, &normal);
-
- pos = ray->pos;
- dir = ray->dir;
- /*
- * Plane intersection.
- */
- k = dotp(&normal, &dir);
- if (fabs(k) < EPSILON)
- return FALSE;
- s = (dotp(&normal, &p0) - dotp(&normal, &pos)) / k;
- if (s < mindist || s > *maxdist)
- return FALSE;
-
- /*
- * Find "dominant" part of normal vector.
- */
- absnorm.x = fabs(normal.x);
- absnorm.y = fabs(normal.y);
- absnorm.z = fabs(normal.z);
-
- if (absnorm.x > absnorm.y && absnorm.x > absnorm.z) {
- qi1 = pos.y + s * dir.y;
- qi2 = pos.z + s * dir.z;
- b0 = (edge2.y * (qi2 - p1.z) -
- edge2.z * (qi1 - p1.y)) / normal.x;
- if (b0 < 0. || b0 > 1.) return FALSE;
- b1 = (edge3.y * (qi2 - p2.z) -
- edge3.z * (qi1 - p2.y)) / normal.x;
- if (b1 < 0. || b1 > 1.) return FALSE;
- b2 = (edge1.y * (qi2 - p0.z) -
- edge1.z * (qi1 - p0.y)) / normal.x;
- if (b2 < 0. || b2 > 1.) return FALSE;
- } else if (absnorm.y > absnorm.z) {
- qi1 = pos.x + s * dir.x;
- qi2 = pos.z + s * dir.z;
- b0 = (edge2.z * (qi1 - p1.x) -
- edge2.x * (qi2 - p1.z)) / normal.y;
- if (b0 < 0. || b0 > 1.) return FALSE;
- b1 = (edge3.z * (qi1 - p2.x) -
- edge3.x * (qi2 - p2.z)) / normal.y;
- if (b1 < 0. || b1 > 1.) return FALSE;
- b2 = (edge1.z * (qi1 - p0.x) -
- edge1.x * (qi2 - p0.z)) / normal.y;
- if (b2 < 0. || b2 > 1.) return FALSE;
- } else {
- qi1 = pos.x + s * dir.x;
- qi2 = pos.y + s * dir.y;
- b0 = (edge2.x * (qi2 - p1.y) -
- edge2.y * (qi1 - p1.x)) / normal.z;
- if (b0 < 0. || b0 > 1.) return FALSE;
- b1 = (edge3.x * (qi2 - p2.y) -
- edge3.y * (qi1 - p2.x)) / normal.z;
- if (b1 < 0. || b1 > 1.) return FALSE;
- b2 = (edge1.x * (qi2 - p0.y) -
- edge1.y * (qi1 - p0.x)) / normal.z;
- if (b2 < 0. || b2 > 1.) return FALSE;
- }
- FractalObjHits++;
- *maxdist = s;
- fractalobj->Normal = normal;
- VecAddScaled(ray->pos, s, ray->dir, &fractalobj->IntersectPos);
-
- return TRUE;
- }
-
- #define VecEqual(a,b) ((equal((a).x, (b).x)) && (equal((a).y, (b).y)) && (equal((a).z, (b).z)))
-
- /*
- * Calculate Normal on triangle at pos
- */
- int FractalObjNormal(fractalobj, pos, nrm, gnrm)
- FractalObj *fractalobj;
- Vector *pos, *nrm, *gnrm;
- {
- if (!VecEqual(*pos, fractalobj->IntersectPos))
- RLerror(RL_ABORT, "Can't compute fractalobj normal in point other than the last intersection.\n");
- *gnrm = fractalobj->Normal;
-
- VecNormalize(gnrm);
- *nrm = *gnrm;
- return FALSE;
- }
-
-
- char *FractalObjName()
- {
- return fractalobjName;
- }
-
- void FractalObjStats(tests, hits)
- unsigned long *tests, *hits;
- {
- *tests = FractalObjTests;
- *hits = FractalObjHits;
- }
-
- void FractalObjBounds(fractalobj, bounds)
- FractalObj *fractalobj;
- Float bounds[2][3];
- {
- int i, j;
- SubObject *CurrSubobject;
-
- for (i = 0; i <= 2; i++) {
- bounds[LOW][i] = MAXVALUE;
- bounds[HIGH][i] = -MAXVALUE;
- }
-
- for(CurrSubobject = fractalobj->SubObjects; CurrSubobject; CurrSubobject = CurrSubobject->Next)
- for (i = 0; i <= 2; i++) {
- bounds[LOW][i] = min(bounds[LOW][i], CurrSubobject->Bounds[LOW][i]);
- bounds[HIGH][i] = max(bounds[HIGH][i], CurrSubobject->Bounds[HIGH][i]);
- }
- for (i = 0; i <= 2; i++)
- for (j = 0; j <= 1; j++)
- fractalobj->Bounds[j][i] = bounds[j][i];
- }
-
- void FractalObjMethodRegister(meth)
- UserMethodType meth;
- {
- if (iFractalObjMethods)
- iFractalObjMethods->user = meth;
- }
-
-
- Methods *FractalObjMethods()
- {
- if (iFractalObjMethods == (Methods *)NULL) {
- iFractalObjMethods = MethodsCreate();
- iFractalObjMethods->create = (GeomCreateFunc *)FractalObjCreate;
- iFractalObjMethods->methods = FractalObjMethods;
- iFractalObjMethods->name = FractalObjName;
- iFractalObjMethods->intersect = FractalObjIntersect;
- iFractalObjMethods->normal = FractalObjNormal;
- iFractalObjMethods->bounds = FractalObjBounds;
- iFractalObjMethods->stats = FractalObjStats;
- iFractalObjMethods->checkbounds = FALSE;
- iFractalObjMethods->closed = FALSE;
- }
- return iFractalObjMethods;
- }
-